#include "serwer.hpp"
#include <iostream>
#include <cliext\algorithm>
#include "ramka.hpp"

using namespace System;
using namespace System::Threading;

Serwer::Serwer(short port) : aktywnychPolaczen(0) {
	ioService = new boost::asio::io_service();
   serwer = new SerwerTCP(*ioService,port);
}

void Serwer::startuj() {
   glownyWatekSerwera = gcnew Thread(gcnew ThreadStart
				     (this,&Serwer::nasluchuj));
   glownyWatekSerwera->Start();
}

void Serwer::nasluchuj() {
   for(;;) {
	   std::cout << "Watek glowny" << std::endl;
	   
	   PolaczenieWrapper^ polaczenie = gcnew PolaczenieWrapper(serwer->akceptuj());
	   Monitor::Enter(wektorPolaczen);
      wektorPolaczen.push_back(polaczenie); //watek sie blokuje na tym
	  Monitor::Exit(wektorPolaczen);
      pulaWatkow.push_back(gcnew Thread
			   (gcnew ParameterizedThreadStart(this,&Serwer::odbieranie)));
      pulaWatkow.back()->Start(wektorPolaczen.back());

   }
}

void Serwer::odbieranie(Object^ obj) {

   std::string wiadomosc;
   for(;;) {
      boost::shared_ptr<boost::asio::ip::tcp::socket> sock = (dynamic_cast<PolaczenieWrapper^>(obj))->polaczenie->getSocketPtr();
      try {
	 
	 wiadomosc = serwer->odbierz(sock);
	 //serwer->wyslij(sock,Ramka::stworzRamkeDoWyslania
			//(logowanieTCP, wiadomosc));

	 //najpierw sprawdzenie, czy ramka jest poprawna
	 Ramka ramka;
	 try {
	    ramka.sprawdzRamkeOdebrana(wiadomosc);
		ramka.ustawOdKogo(dynamic_cast<PolaczenieWrapper^>(obj)->polaczenie->getId());
	    nowaRamka(ramka,dynamic_cast<PolaczenieWrapper^>(obj)->polaczenie);
	 } catch (...) {
	    // ramka byla bledna wiec ja ignorujemy i czekamy dalej
	 }


      } catch(...) {
	 Monitor::Enter(wektorPolaczen);
	 wektorPolaczen.erase(cliext::find(wektorPolaczen.begin(), wektorPolaczen.end(), dynamic_cast<PolaczenieWrapper^>(obj)));
	 Monitor::Exit(wektorPolaczen);
	 symulator->wyloguj(dynamic_cast<PolaczenieWrapper^>(obj)->polaczenie->getId());
	 break; //przerywamy for, wiec watek powinien zakonczyc dzialanie...
      }
   }
   symulator->wyloguj(dynamic_cast<PolaczenieWrapper^>(obj)->polaczenie->getId());
}

void Serwer::nowaRamka(Ramka ramka, Polaczenie* sock) {
   switch(ramka.pobierzTemat()) {
   case logowanieTCP:
      //tutaj  logowanie
	   if(!(symulator->zaloguj(ramka.pobierzOdKogo(),ramka.pobierzLogin(),ramka.pobierzHaslo()))) {
			//serwer->zamknij(sock->getSocketPtr());   
	   }
	   //duza aktualizacja danych przy logowaniu
	   serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
		      (nowaMapaObiektowTCP, Ramka::zamienMapeCLINaString
		      (symulator->pobierzMapeObiektow())));
      serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
		      (nowaMapaWartZadTCP, Ramka::zamienMapeCLINaString
		      (symulator->pobierzMapeWartZad())));
	  serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
		      (nowaMapaRegulatorowTCP, Ramka::zamienMapeCLINaString
		      (symulator->pobierzMapeRegulatorow())));
      
	 serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
			 (zmianaRegulatoraTCP, Ramka::zamienMapeNaString
			  (symulator->pobierzKonfigRegulatora())));
	 
	 serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
			 (zmianaObiektuTCP, Ramka::zamienMapeNaString
			  (symulator->pobierzKonfigObiektu())));	 	  
	serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania
		      (nowaListaUstawionychGeneratorowTCP,
		       Ramka::zamienWektorCLINaString
		       (symulator->pobierzListeUstawionychGeneratorow())));
      break;
   case wylogowanieTCP:
      break;
   
   case nowaMapaRegulatorowTCP:         
	  serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania(nowaMapaRegulatorowTCP,Ramka::zamienMapeCLINaString(symulator->pobierzMapeRegulatorow())));
      break;

   case nowaMapaObiektowTCP:
      serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania(nowaMapaObiektowTCP,Ramka::zamienMapeCLINaString(symulator->pobierzMapeObiektow())));
      break;

			   
   case nowaMapaWartZadTCP:
      serwer->wyslij(sock->getSocketPtr(),Ramka::stworzRamkeDoWyslania(nowaMapaWartZadTCP,Ramka::zamienMapeCLINaString(symulator->pobierzMapeWartZad())));
      break;

   case resetSymulacjiTCP:
	  symulator->symulatorReset(fingerprint, ramka.pobierzOdKogo());   
	  break;

   case stopSymulacjiTCP:
	   symulator->symulatorStop(fingerprint, ramka.pobierzOdKogo());   
	   break;

   case startSymulacjiTCP:
	  symulator->symulatorStart(fingerprint, ramka.pobierzOdKogo());   
	  break;

   case zmianaObiektuTCP:
	   symulator->ustawObiekt(Ramka::ToSysString(ramka.pobierzDane()),fingerprint,ramka.pobierzOdKogo());
	   break;
    case zmianaRegulatoraTCP:
	   symulator->ustawRegulator(Ramka::ToSysString(ramka.pobierzDane()),fingerprint,ramka.pobierzOdKogo());
	   break;
	case nowaListaUstawionychGeneratorowTCP:
	   symulator->dodajWartZad(Ramka::ToSysString(ramka.pobierzDane()),fingerprint,ramka.pobierzOdKogo());
	   break;
   }		
}


void Serwer::obserwuj(ObiektObserwowalny^ obiektObserwowalny) {
   obiektObserwowalny->dodajObserwatora(this);
   symulator = dynamic_cast<Symulator^>(obiektObserwowalny);
   fingerprint = gcnew Autoryzowany();
   symulator->ustawAutoryzowanySerwer(fingerprint);
}

void Serwer::wyslijWszystkim(std::string wiadomosc) {
   Monitor::Enter(wektorPolaczen);
   cliext::vector<PolaczenieWrapper^>::iterator it = wektorPolaczen.begin();
   for(; it != wektorPolaczen.end(); ++it) {
      serwer->wyslij(it->polaczenie->getSocketPtr(), wiadomosc);
   }
   Monitor::Exit(wektorPolaczen);	
}

void Serwer::aktualizuj(int zdarzenie) {

   switch (zdarzenie) {
   case TematAktualizacji::nowaMapaRegulatorow:
      wyslijWszystkim(Ramka::stworzRamkeDoWyslania(nowaMapaRegulatorowTCP, Ramka::zamienMapeCLINaString(symulator->pobierzMapeRegulatorow())));
      break;

   case TematAktualizacji::nowaMapaObiektow:
      wyslijWszystkim(Ramka::stworzRamkeDoWyslania
		      (nowaMapaObiektowTCP, Ramka::zamienMapeCLINaString
		      (symulator->pobierzMapeObiektow())));

      break;
			   
   case TematAktualizacji::nowaMapaWartZad:
      wyslijWszystkim(Ramka::stworzRamkeDoWyslania
		      (nowaMapaWartZadTCP, Ramka::zamienMapeCLINaString
		      (symulator->pobierzMapeWartZad())));
      break;
			   
   case TematAktualizacji::zmianaRegulatora:
      try {
	 wyslijWszystkim(Ramka::stworzRamkeDoWyslania
			 (zmianaRegulatoraTCP, Ramka::zamienMapeNaString
			  (symulator->pobierzKonfigRegulatora())));
	 
      } catch(...) {
	 wyslijWszystkim(Ramka::stworzRamkeDoWyslania
			 (czyscRegulatorTCP, std::string()));
      }
      break;

   case TematAktualizacji::zmianaObiektu:
      try {
	 wyslijWszystkim(Ramka::stworzRamkeDoWyslania
			 (zmianaObiektuTCP, Ramka::zamienMapeNaString
			  (symulator->pobierzKonfigObiektu())));
	 
      } catch(...) {
	 wyslijWszystkim(Ramka::stworzRamkeDoWyslania
			 (czyscObiektTCP, std::string()));
      }
      break;

   case TematAktualizacji::nowaListaUstawionychGeneratorow:
      
      wyslijWszystkim(Ramka::stworzRamkeDoWyslania
		      (nowaListaUstawionychGeneratorowTCP,
		       Ramka::zamienWektorCLINaString
		       (symulator->pobierzListeUstawionychGeneratorow())));

      break;

   case TematAktualizacji::nowyKrokSymulacji:
      wyslijWszystkim(Ramka::stworzRamkeDoWyslania
		  (NowyKrokSymulacjiTCP,
		       Ramka::zamienWektorDoubleNaString
		       (symulator->pobierzAktualneWartosci())));
      break;

   case TematAktualizacji::resetSymulacji:
	   wyslijWszystkim(Ramka::stworzRamkeDoWyslania
		  (resetSymulacjiTCP, std::string()));
	   break;

	   //case TematAktualizacji
   }
}
